package br.unicarioca.viaexpositus.ases;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import br.org.acessobrasil.ases.ferramentas_de_reparo.controle.XHTMLControle;
import br.org.acessobrasil.ases.nucleo.InterfClienteDoNucleo;
import br.org.acessobrasil.ases.nucleo.NucleoEstruturado;
import br.org.acessobrasil.ases.nucleo.adapters.entidade.ArmazenaErroOuAviso;
import br.org.acessobrasil.ases.regras.RegrasHardCodedEmag;

/**
 * Cliente do ASES para validacao de acessibilidade
 * @author Fabio Issamu Oshiro
 *
 */
public class AsesCliente implements InterfClienteDoNucleo{
	private int correcaoLinha = 0;
	private NucleoEstruturado nucleo;
	private RegrasHardCodedEmag regras = new RegrasHardCodedEmag();
	private boolean errado=false;
	private RelatorioAcessibilidade relatorio;
	private ArrayList<ErrosRegra> listErroP1 = new ArrayList<ErrosRegra>();
	private ArrayList<ErrosRegra> listErroP2 = new ArrayList<ErrosRegra>();
	private ArrayList<ErrosRegra> listErroP3 = new ArrayList<ErrosRegra>();
	private ArrayList<ErrosRegra> listErroXHTML = new ArrayList<ErrosRegra>();
	private ArrayList<ErrosRegra> listAvisoP1 = new ArrayList<ErrosRegra>();
	private ArrayList<ErrosRegra> listAvisoP2 = new ArrayList<ErrosRegra>();
	private ArrayList<ErrosRegra> listAvisoP3 = new ArrayList<ErrosRegra>();

	private List<ArmazenaErroOuAviso> avisoP1;
	private List<ArmazenaErroOuAviso> avisoP2;
	private List<ArmazenaErroOuAviso> avisoP3;
	private List<ArmazenaErroOuAviso> avisoXHTML=new ArrayList<ArmazenaErroOuAviso>();
	private List<ArmazenaErroOuAviso> erroP1;
	private List<ArmazenaErroOuAviso> erroP2;
	private List<ArmazenaErroOuAviso> erroP3;
	private List<ArmazenaErroOuAviso> erroXHTML=new ArrayList<ArmazenaErroOuAviso>();

	static {
		//Configura o idioma do ases
		br.org.acessobrasil.silvinha.util.lang.TokenLang.LANG="pt";
	}

	public AsesCliente(){
		nucleo = new NucleoEstruturado();
		nucleo.addCliente(this);
	}

	/**
	 * Configura o caminho do path
	 * Ex.: http://www.seusite.com.br/dtd
	 * @param path
	 */
	public static void setDtdBasePath(String path){
		//Configura o local dos DTDs
		XHTMLControle.XHTML_01Strict="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \""+path+"/xhtml1-strict.dtd\">";
		XHTMLControle.HTML4_01Strict="<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Strict//EN\" \""+path+"/html4.01strict.dtd\">";
		XHTMLControle.HTML4_01Transitional="<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \""+path+"/html4.01transitional.dtd\">";
		XHTMLControle.HTML4_01Frameset="<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML Frameset//EN\" \""+path+"/html4.01frameset.dtd\">";
	}

	/**
	 * Fecha as tags (br,img)
	 * Coloca as tags em minúsculas
	 * @param conteudoFormatado
	 */
	public String tratar(String conteudo){
		return conteudo
			.replaceAll("<img\\s([^>]*[^/])>","<img $1 />")
			.replace("<br>", "<br />");
	}
	/**
	 * Avalia o padrão html em lowerCase <br>
	 * Avalia a Acessibilidade com casesensitive <br>
	 *
	 * @param html código html
	 */
	public void avalia(String html){
		nucleo.setRegras(regras);
		nucleo.setCodHTML(html);
		nucleo.setAvaliaCSS(false);
		try {
			nucleo.setCodWcagEmag(NucleoEstruturado.EMAG);
			nucleo.setWCAGEMAG(NucleoEstruturado.EMAG);
		} catch (RuntimeException e) {
			e.printStackTrace();
		}
		nucleo.avalia();

		reavalia(html.replace("&","&amp;"));
	}
	/**
	 * Organiza o array armazenaErroOuAviso
	 * por ErrosRegra
	 */
	private void organizaErroOuAviso(ArrayList<ErrosRegra> lista,ArrayList<ArmazenaErroOuAviso> armazenaErroOuAviso){
		//Coloca no hashmap de forma ordenada
		HashMap<String,ArrayList<ArmazenaErroOuAviso>> mapa = new HashMap<String,ArrayList<ArmazenaErroOuAviso>>();
		for(int i=0;i<armazenaErroOuAviso.size();i++){
			if(!mapa.containsKey(armazenaErroOuAviso.get(i).getIdTextoRegra())){
				mapa.put(armazenaErroOuAviso.get(i).getIdTextoRegra(), new ArrayList<ArmazenaErroOuAviso>());
			}
			armazenaErroOuAviso.get(i).setLinha(armazenaErroOuAviso.get(i).getLinha()+correcaoLinha);
			mapa.get(armazenaErroOuAviso.get(i).getIdTextoRegra())
			.add(armazenaErroOuAviso.get(i));
		}
		Map<String, ArrayList<ArmazenaErroOuAviso>> sortedMap = new TreeMap<String, ArrayList<ArmazenaErroOuAviso>>(mapa);
		List<String> mapKeys = new ArrayList<String>(sortedMap.keySet());
		ArrayList<ArrayList<ArmazenaErroOuAviso>> mapValues = new ArrayList<ArrayList<ArmazenaErroOuAviso>>(sortedMap.values());
		for(int i=0;i<mapKeys.size();i++){
			ErrosRegra errosRegra = new ErrosRegra();
			errosRegra.setCodigo(mapKeys.get(i));
			errosRegra.setTexto(regras.getTextoRegra(mapKeys.get(i)));
			errosRegra.setListOcorrencia(mapValues.get(i));
			lista.add(errosRegra);
		}
	}

	public void avisosP1(ArrayList<ArmazenaErroOuAviso> armazenaErroOuAviso) {
		avisoP1 = armazenaErroOuAviso;
		organizaErroOuAviso(listAvisoP1, armazenaErroOuAviso);
	}

	private void reavalia(String codigo) {
		try {
			XHTMLControle xhtmlValidator = new XHTMLControle();
			try {
				xhtmlValidator.avalia(codigo);
			} catch (RuntimeException e) {
				e.printStackTrace();
			}
			for (int i = 0; i < xhtmlValidator.length(); i++) {
				ErrosRegra errosRegra1=new ErrosRegra();

				errosRegra1.setTexto(xhtmlValidator.getMensagem(i));

				List<ArmazenaErroOuAviso> armazenaErrosOuAvisos=new ArrayList<ArmazenaErroOuAviso>();
				ArmazenaErroOuAviso armazenaErroOuAviso=new ArmazenaErroOuAviso();
				armazenaErroOuAviso.setLinha(xhtmlValidator.getLinha(i));
				armazenaErroOuAviso.setColuna(xhtmlValidator.getColuna(i));
				avisoXHTML.add(armazenaErroOuAviso);
				erroXHTML.add(armazenaErroOuAviso);
				armazenaErrosOuAvisos.add(armazenaErroOuAviso);
				errosRegra1.setListOcorrencia(armazenaErrosOuAvisos);

				listErroXHTML.add(errosRegra1);
				//retirado por bug em DTD
				errado=true;
			}
			getRelatorio();
			// domValidator
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void avisosP2(ArrayList<ArmazenaErroOuAviso> armazenaErroOuAviso) {
		avisoP2 = armazenaErroOuAviso;
		organizaErroOuAviso(listAvisoP2, armazenaErroOuAviso);
	}


	public void avisosP3(ArrayList<ArmazenaErroOuAviso> armazenaErroOuAviso) {
		avisoP3 = armazenaErroOuAviso;
		organizaErroOuAviso(listAvisoP3, armazenaErroOuAviso);
	}


	public void errosP1(ArrayList<ArmazenaErroOuAviso> armazenaErroOuAviso) {
		if(armazenaErroOuAviso!=null && armazenaErroOuAviso.size()>0){
			errado=true;
		}
		erroP1=armazenaErroOuAviso;
		organizaErroOuAviso(listErroP1, armazenaErroOuAviso);

	}


	public void errosP2(ArrayList<ArmazenaErroOuAviso> armazenaErroOuAviso) {
		if(armazenaErroOuAviso!=null && armazenaErroOuAviso.size()>0){
			errado=true;
		}
		erroP2=armazenaErroOuAviso;
		organizaErroOuAviso(listErroP2, armazenaErroOuAviso);
	}


	public void errosP3(ArrayList<ArmazenaErroOuAviso> armazenaErroOuAviso) {
		if(armazenaErroOuAviso!=null && armazenaErroOuAviso.size()>0){
			errado=true;
		}
		erroP3=armazenaErroOuAviso;
		organizaErroOuAviso(listErroP2, armazenaErroOuAviso);

	}


	public void fimDaAvaliacao() {

	}

	public RelatorioAcessibilidade getRelatorio(){
		//gerar o relatorio
		if(relatorio!=null) return relatorio;
		relatorio = new RelatorioAcessibilidade();
		relatorio.setListAvisoP1(listAvisoP1);
		relatorio.setListAvisoP2(listAvisoP2);
		relatorio.setListAvisoP3(listAvisoP3);

		relatorio.setListErroP1(listErroP1);
		relatorio.setListErroP2(listErroP2);
		relatorio.setListErroP3(listErroP3);
		relatorio.setListErroXHTML(listErroXHTML);

		//imprimeListaErr(listErroP1);
		//imprimeListaErr(listErroP2);
		//imprimeListaErr(listErroP3);
		return relatorio;
	}

	public void linksAchadosPeloNucleo(HashSet<String> arg0) {
		// TODO Auto-generated method stub

	}
	public boolean isErrado() {
		return errado;
	}
	public List<ArmazenaErroOuAviso> getListErroP1() {
		return erroP1;
	}
	public List<ArmazenaErroOuAviso> getListErroP2() {
		return erroP2;
	}
	public List<ArmazenaErroOuAviso> getListErroP3() {
		return erroP3;
	}
	public RegrasHardCodedEmag getRegras() {
		return regras;
	}
	public List<ArmazenaErroOuAviso> getAvisoP1() {
		return avisoP1;
	}
	public List<ArmazenaErroOuAviso> getAvisoP2() {
		return avisoP2;
	}
	public List<ArmazenaErroOuAviso> getAvisoP3() {
		return avisoP3;
	}
	public void setCorrecaoLinha(int i) {
		correcaoLinha = i;
	}




	public List<ArmazenaErroOuAviso> getErroXHTML() {
		return erroXHTML;
	}


}

